Repository navigation
Conversation
…-1076) edgeauth verifies the x-bastion-identity JWT guard sends upstream (ES256, typ bastion-id+jwt, iss bastion, aud in the app's hosts, exp/iat with 10 s leeway) against guard's JWKS, fetched lazily, cached 5 min and refetched for an unknown kid at most once per 30 s. Middleware puts the identity in the context, answers 401 for an invalid token and 503 when the keys are unreachable; RequireIdentity and RequireRole refuse anonymous and unauthorised callers. edgeauthtest mints identities for app tests. @metsaapp/edgeauth is the TypeScript twin on jose, installable from this repository by tag. Both run the conformance vectors in edgeauth/testdata/vectors.json. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MwB9uUtkK8BFT7ZGoXwX9u
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The shared verifier for guard's identity JWT (contract COR-1073 §2, §3, §10), in Go and TypeScript, with conformance vectors both run.
edgeauth/:Verifierwith ES256 only,typbastion-id+jwt (compared the RFC 7515 / jose way: case-insensitive,application/optional), a knownkid,issbastion,audinConfig.Audiences,exp/iat(andnbfwhen present) with 10 s leeway,subrequired. The JWKS is fetched lazily (never inNew) and cached 5 min. An unknown kid triggers at most one refetch per 30 s, and fetches are single-flight. A failed fetch is remembered for 5 s, and keys that were cached before still verify during an outage. go-jose v4 does the JWS parsing and signature check (it was already in the module graph); the claim rules are written out by hand so they match the TS side exactly.Middleware: no header → anonymous.ErrInvalid→ 401, logged throughWithLogger.ErrUnavailable→ 503. Bodies are plain text and never echo the token.RequireIdentity,RequireRole(any of; 401/403),FromContext/ContextWith,Identity.HasRole/HasAnyRole.edgeauth/edgeauthtest:NewIssuer(t)(in-memory P-256 key, httptest JWKS closed byt.Cleanup),Config,Mint,MintWith(id, aud, func(*Claims))for expired or wrong-aud tokens,Sign(aud =r.Host, lower case, no port).edgeauth/testdata/vectors.json: 32 cases generated bygo generate ./edgeauth(internal/vectorgen). The JWS is assembled by hand with deterministic RFC 6979 signatures, and a test fails when the committed file is stale. Cases: valid session/bearer, empty/absent roles, leeway edges for exp and iat, future iat/nbf, wrong/upper-case aud, aud array, wrong iss, HS256 key-confusion, alg none, wrong/missing typ, unknown/missing kid, foreign-key signature, DER signature, tampered payload, wrong claim types, missing sub/exp/iat, a non-JWS, JWKS unreachable → unavailable.ts/edgeauth/+ rootpackage.json(@metsaapp/edgeauth):createVerifier({jwksUrl?, audiences, now?})→{verify, fromHeaders}, built on jose (createRemoteJWKSetwith cacheMaxAge 5 min, cooldown 30 s, timeout 5 s;jwtVerifywith ES256, typ, issuer, audience, clockTolerance 10, plus the iat-not-ahead check jose skips). Errors areEdgeAuthInvalid/EdgeAuthUnavailable.edgeauth-ts: runsnpm ci, checks the jose ranges agree, type-checks, checks the committeddistmatches the source, then runs vitest under Node and under Bun.PLATFORM_KIT_EDGEAUTH_*added to the runtime contract's variables.API additions beyond the contract (nothing renamed)
ConfigFromEnv(),ErrConfig,WithLogger, constsIssuer,TokenType,DefaultJWKSURL,Leeway,SourceSession/SourceBearer;edgeauthtest.MintWith,Claims,JWKSURL(),KeyID,Lifetime.NewIssuertakestesting.TB.RequireRole()with no roles behaves likeRequireIdentity. Interpretation: "iat not more than 60 s ahead" is implemented as iat ≤ now + 10 s leeway (guard sets iat = now).Packaging decisions
dist: Bun and pnpm do not run lifecycle scripts of git dependencies, so apreparebuild is unreliable. Bun imports the TS source through thebunexport condition. Node and bundlers getdist/index.js+.d.ts.filesis limited tots/edgeauthsrc/dist. I installed this commit withnpm install @metsaapp/edgeauth@git+file://…#<sha>andbun addand imported it under both runtimes.ts/edgeauth/package.json, lockfile, node_modules) stays underts/. A stubts/go.modkeeps./..., golangci-lint and the Go module zip out of it. The rootpackage.jsonhas no devDependencies.package.jsonversionis inextra-files, so it bumps with each Go release. The release type staysgo.Test evidence
go build ./... && go vet ./... && go test -race ./...: ok (edgeauth, natsclient, runtime)go run github.com/golangci/golangci-lint/v2/cmd/[email protected] run: 0 issuesnpm run check && npm run typecheck && npm run build && npm test: 37 passed.bun --bun x vitest run: 37 passed. dist matches the source.Apps pin a pseudo-version of this branch until it is released (
go get github.com/MetsaApp/platform-kit@338c1157e883d35133bfc66b537420da61267397, which resolves tov0.2.1-0.20261030231032-338c1157e883); release-please cuts v0.3.0 on merge.Generated by Claude Code